#include <stddef.h>
#include <iostream>
#include <atomic>

template<class T>
class myptr
{
	typedef T element_type;
private:
	element_type* m_ptr;
	std::atomic<size_t>* m_counter;

public:
	myptr()
		:m_ptr(nullptr), m_counter(nullptr)
	{
		std::cout << this << ":myptr()" << std::endl;
	}

	explicit myptr(element_type* ptr)
		:m_ptr(ptr), m_counter(new std::atomic<size_t>(1))
	{
		std::cout << this << ":myptr(T* ptr)" << std::endl;
	}

	constexpr myptr(nullptr_t) //用nullptr创建智能指针时触发，constexpr表示在编译期就可以确定
		:myptr() //调用无参构造函数初始化
	{
		std::cout << this << ":myptr(nullptr_t)" << std::endl;
	}

	//拷贝构造
	myptr(const myptr& other)
	{
		std::cout << this << ":myptr(const myptr& other)" << std::endl;
		m_ptr = other.m_ptr;
		m_counter = other.m_counter;
		if(m_counter)
		{
			(*m_counter)++;
		}
	}

	//移动构造
	myptr(myptr&& other)
	{
		std::cout << this << ":myptr(myptr&& other)" << std::endl;
		m_ptr = other.m_ptr;
		m_counter = other.m_counter;

		other.m_ptr = nullptr;
		other.m_counter = nullptr;
	}

    ~myptr()
	{
		std::cout << this << ":~myptr()" << std::endl;
        //销毁当前智能指针

		if(!m_ptr || !m_counter)
		{
			return;
		}
		(*m_counter)--;
		if (*m_counter == 0)
		{
			delete m_ptr;
			m_ptr = nullptr;

			delete m_counter;
			m_counter = nullptr;
		}
	}

	//赋值运算符
	myptr& operator=(const myptr& other)
	{
		std::cout << this << ":operator=(const myptr& other)" << std::endl;
		if(this != &other) //避免自己赋值给自己
		{
			myptr(other).swap(*this);
		}
		return *this;
	}

	//移动赋值
	myptr& operator=(myptr&& other)
	{
		std::cout << this << ":operator=(myptr&& other)" << std::endl;
		if(this != &other) //避免自己赋值给自己
		{
			myptr(std::move(other)).swap(*this);
		}
		return *this;
	}

    void swap(myptr& other)
    {
        if(this == &other)
        {
            return;
        }
        std::swap(m_counter, other.m_counter);
        std::swap(m_ptr, other.m_ptr);
    }

	//成员访问运算符重载
	element_type* operator->() const //不加const常量对象就无法使用该运算符
	{
		return m_ptr;
	}

	//解引用运算符重载
	element_type& operator*() const //不加const常量对象就无法使用该运算符
	{
		if(!m_ptr)
		{
			throw std::runtime_error("Dereferencing null pointer");
		}
		return *m_ptr;
	}

	//类型转换运算符重载
	explicit operator bool() const //不加const常量对象就无法使用该运算符，explicit防止隐式转换（比如对智能指针偏移运算）
	{
		return bool(m_ptr);
	}

	element_type* get() const //不加const常量对象就无法使用该函数
	{
		return m_ptr;
	}

	size_t use_count() const
	{
		if(!m_counter)
		{
			return 0;
		}
		return *m_counter;
	}

	void reset()
	{
		myptr().swap(*this);
	}

	void reset(element_type* ptr)
	{
		myptr(ptr).swap(*this);
	}
};